using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace SOEN341_SCHEDULER_PHASE1
{
    [Serializable()]
    class Course : ISerializable
    {
        #region MEMBER_VARIABLES

        private string _name;
        private string _section;
        private TimeTableBlock _ttb;
        private int _size;
        private List<Student> _studentRegistered;
        private List<Course> _preq;
        private string _courseName;
        private int _capacity;
        private int _credits;
        private Course _labCourse;
        private Course _tutorialCourse;
        public GlobalVariablesClass.ErrorCodes _errCode;
        public Object[] Tag;
        private bool _isTutorialOrLab;
        #endregion

        
        #region SERIALIZATION
        /// <summary>
        /// Serialized Constructor
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public Course(SerializationInfo info, StreamingContext ctxt)
        {
            //Get the values from info and assign them to the appropriate properties

            _name = (string)info.GetValue("name", typeof(string));
            _section = (string)info.GetValue("section", typeof(string));
            _ttb = (TimeTableBlock)info.GetValue("ttb", typeof(TimeTableBlock));
            _size = (int)info.GetValue("size", typeof(int));
            _studentRegistered = (List<Student>)info.GetValue("studentRegistered", typeof(List<Student>));
            _preq = (List<Course>)info.GetValue("preq", typeof(List<Course>));
            _courseName = (string)info.GetValue("courseName", typeof(string));
            _capacity = (int)info.GetValue("capacity", typeof(int));
            _credits = (int)info.GetValue("credits", typeof(int));
            _labCourse = (Course)info.GetValue("lc", typeof(Course));
            _tutorialCourse = (Course)info.GetValue("tc", typeof(Course));
            _isTutorialOrLab = (bool)info.GetValue("isTut", typeof(bool));
        }

        /// <summary>
        /// Serialization method
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("name", _name);
            info.AddValue("section", _section);
            info.AddValue("ttb", _ttb);
            info.AddValue("size", _size);
            info.AddValue("studentRegistered", _studentRegistered);
            info.AddValue("preq", _preq);
            info.AddValue("courseName", _courseName);
            info.AddValue("capacity", _capacity);
            info.AddValue("credits", _credits);
            info.AddValue("lc", _labCourse);
            info.AddValue("tc", _tutorialCourse);
            info.AddValue("isTut", _isTutorialOrLab);
        }
        #endregion

        #region CONSTRUCTORS

        /// <summary>
        /// Default Constructor
        /// </summary>
        public Course()
        {
            _name = "UNDEFINED";
            _section = "N/A";
            _ttb = null;
            _size = 0;
            _studentRegistered = new List<Student>();
            _preq = new List<Course>();
            _courseName = "UNDEFINED";
            _capacity = 0;
            _credits = 0;
        }

        /// <summary>
        /// Parameterized constructor
        /// </summary>
        /// <param name="name">Course name</param>
        /// <param name="courseName">Course mnemonics (COMPXXX)</param>
        /// <param name="section">Course section</param>
        /// <param name="ttb">Time/Date</param>
        /// <param name="description">Course description</param>
        /// <param name="preq">Prerequistes needed</param>
        /// <param name="capacity">Max place</param>
        public Course(string name, string courseName,string section, TimeTableBlock ttb, List<Course> preq, Course tutorialCourse,Course labCourse, int capacity, int credits)
        {
            _capacity = capacity;
            _courseName = courseName;
            _name = name;
            _section = section;
            _ttb = ttb;
            _preq = new List<Course>();
            _credits = credits;

            if (preq != null)
            {
                Course[] tempPreq = preq.ToArray();
                for (int i = 0; i < tempPreq.Length; i++)
                {
                    _preq.Add(tempPreq[i]);
                }

            }

            _tutorialCourse = tutorialCourse;
            _labCourse = labCourse;

            _size = 0;
            _studentRegistered = new List<Student>();

            if (_tutorialCourse == null)
            {
                _isTutorialOrLab = true;
            }
            else
            {
                _isTutorialOrLab = false;
            }
            if (ttb != null)
            {
                ttb.SetSubject(_courseName);
            }
        }
        #endregion

        #region ACCESSOR_FUNCTIONS

        /// <summary>
        /// Property used to display Course in ListBox
        /// </summary>
        public string CourseNameProperty
        {
            get { return _courseName; }
            
        }

        /// <summary>
        /// Get the tutorial course
        /// </summary>
        /// <returns>Returns Course - Tutorial (NULL: No tutorial)</returns>
        public Course GetTutorial()
        {
            return _tutorialCourse;
        }

        /// <summary>
        /// Get the Lab course
        /// </summary>
        /// <returns>Return Course - Tutorial (NULL: No lab)</returns>
        public Course GetLab()
        {
            return _labCourse;
        }

        public int GetNumberOfCredits()
        {
            return _credits;
        }

        /// <summary>
        /// Get course capacity
        /// </summary>
        /// <returns>Course capacity</returns>
        public int GetCapacity()
        {
            return _capacity;
        }

        /// <summary>
        /// Get list of registered students
        /// </summary>
        /// <returns>List of currently registered students</returns>
        public List<Student> GetRegisteredStudents()
        {
            return _studentRegistered;
        }

        /// <summary>
        /// Get course name
        /// </summary>
        /// <returns>Course name</returns>
        public string GetName()
        {
            return _name;
        }

        /// <summary>
        /// Course mnemonics (COMPXXX)
        /// </summary>
        /// <returns>Course mnemonics</returns>
        public string GetCourseName()
        {
            return _courseName;
        }

        /// <summary>
        /// Get course section
        /// </summary>
        /// <returns>Course section</returns>
        public string GetSection()
        {
            return _section;
        }

        /// <summary>
        /// Get time/date
        /// </summary>
        /// <returns>Course time/date (TimeTableBlock)</returns>
        public TimeTableBlock GetTimeTableBlock()
        {
            return _ttb;
        }

        /// <summary>
        /// Get prerequisites
        /// </summary>
        /// <returns>List of courses (preq)</returns>
        public List<Course> GetPrerequiste()
        {
            return _preq;
        }

        #endregion 

        /// <summary>
        /// Equals method
        /// </summary>
        /// <param name="obj">Object to compare to</param>
        /// <returns>TRUE: EQUALS FALSE: !EQUALS</returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType().Equals(this.GetType()))
            {
                Course temp = (Course)obj;

                return ((_name.Equals(temp.GetName())) && (_section.Equals(temp.GetSection()))
                    && (_ttb.Equals(temp.GetTimeTableBlock())) && 
                    (_preq.Equals(temp.GetPrerequiste())));
            }
            return false;
        }

        /// <summary>
        /// Adds a student to the course (verifies prerequistes)
        /// Error message in _errCode
        /// </summary>
        /// <param name="student">Student to add</param>
        /// <returns>TRUE: added FALSE: not added (check _errCode)</returns>
        public bool AddStudent(Student student)
        {
            //verify prerequistes
            List<Course> tempStudentCourses = student.GetCourseHistory();
            Course[] preq = _preq.ToArray();

            bool isGood = true;

            for (int i = 0; i < preq.Length; i++)
            {
                if (!tempStudentCourses.Contains(preq[i]))
                {
                    isGood = false;
                    break;
                }
            }

            if (isGood && _size<_capacity)
            {
                _studentRegistered.Add(student);
                _size++;
                return true;
            }

            if (isGood)
            {
                _errCode = GlobalVariablesClass.ErrorCodes.Course_ClassFull;
            }
            else
            {
                _errCode = GlobalVariablesClass.ErrorCodes.Course_NoPrerequistes;
            }

            return false;
        }

        /// <summary>
        /// Verifies if class passed has the same course name
        /// </summary>
        /// <param name="toCheck">Course to compare</param>
        /// <returns>TRUE: Same Name FALSE: No match</returns>
        public bool IsSameClassName(Course toCheck)
        {
            return _courseName.Equals(toCheck.GetCourseName());
        }

        /// <summary>
        /// Returns if Course is tutorial or lab
        /// </summary>
        /// <returns>TRUE: TUTORIAL/LAB FALSE: LECTURE</returns>
        public bool IsTutorialOrLab()
        {
            return _isTutorialOrLab;
        }

        /// <summary>
        /// To String method
        /// </summary>
        /// <returns>Returns course info string</returns>
        public override string ToString()
        {
            if (_ttb != null)
            {
                if (!_isTutorialOrLab)
                {
                    return _courseName + " - " + _section + " @ " + _ttb.GetCustomDateTime().GetTimeInterval();
                }
                else
                {
                    return "  " + _courseName + " - " + _section + " @ " + _ttb.GetCustomDateTime().GetTimeInterval();
                }
            }
            else
            {
                return _courseName;
            }
        }
    }
}
